<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script>
  const html = `
  <div class="container">
    <header class="header" id="header">
      <nav>
        <li><a href="http://ssss.com">menu home home home</a></li>
        <li><a href="http://ssss.com">  menu user</a></li>
      </nav>
    </header>
    <main>
      <  section  >
        <ul>
          <li>select 1</li>
          <li>  select 2</li>
          <li>select 3  </li>
          <li>  select 3  </li>
        </ul>
      </section>
      <article>
        <img src="https://image.jpg" /  >
        <div>
          some text
        </div>
      </article>
    <  /  main>
    <footer>
      footer
    </footer>
  </div>
  `

  let tree = null;
  const tagIds = []

  function findTag (str) {
    if (str.trim().length) {
      return str.trim().match(/[a-zA-Z]+/)[0]
    }
  }

  class NodeTag {
    constructor({ id, name, nodeString }) {
      this.id = id;
      this.name = name;
      this.nodeString = nodeString;
      this.children = {};
    }

    setChild (ids, child) {
      const [id, childId, ...__ids] = ids

      if (id === this.id) {
        if (this.children[childId]) {
          this.children[childId].setChild([childId, ...__ids], child)
        } else {
          child.parent = this;
          this.children[childId] = child
        }
      } else {
        console.log('id is not find')
      }
    }
  }

  html.replace(/<[^>]+>|((?<=[^<]).+?(?=<))/gms, (nodeString) => {
    const name = findTag(nodeString)
    if (!name) return;

    nodeString = nodeString.replace(/<\s*/, '<')
    nodeString = nodeString.replace(/\s*>/, '>')

    if (nodeString.startsWith('</')) {
      nodeString = nodeString.replace(/<\/\s*/, '<\/')
    }

    if (nodeString.startsWith('</')) {
      tagIds.pop()
      return nodeString
    }

    const node = {
      id: Math.abs(Math.random() * Math.pow(10, 10)),
      name, nodeString
    }

    if (nodeString.startsWith('<')) {
      node.type = 'element'
      if (!nodeString.endsWith('/>')) {
        tagIds.push(node.id)
      }
    } else {
      tagIds.push(node.id)
      node.type = 'text'
    }

    if (!tree) {
      tree = new NodeTag(node)
    } else {
      tree.setChild(tagIds, new NodeTag(node))
    }

    if (!nodeString.startsWith('<')) {
      tagIds.pop()
    }

    return nodeString
  })

  // 解析后的数组 重新构造为 【树形结构】
  console.log(tree)
</script>
</body>
</html>
